﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using DiscoveryLogic.UI.Layouts.Converters;
using DiscoveryLogic.UI.Layouts.Models;
using DiscoveryLogic.UI.Layouts.Controls;
using System.Collections.Generic;
using System.Windows.Controls.Primitives;
using DiscoveryLogic.UI.Layouts.DataAcccesses;
using DiscoveryLogic.DataServices.DataSources;

namespace DiscoveryLogic.UI.Layouts.ContentScreens
{
    public partial class Portfolio : UserControl
    {

        #region Private Variables

            private ToggleButton[] investmentStyleButtons = new ToggleButton[5];
            private PieOverlay[] investmentStyleOverlays = new PieOverlay[5];
            private FundLegend[] fundLegendIcons = new FundLegend[6];
            private List<EnrollmentFund> fundPanelList;
            private MouseManager mouseEventManager;
            private FundsManager fundManager;

            private PieChart portfolioPie;
            private PieOverlay currentOverlay;
            private ToggleButton currentInvestmentStyleButton;

            private List<FundTypes> missingFundTypes;
            private List<FundTypes> unwantedFundTypes;

            Dictionary<PieSlice, double> allocationOverTable;
            Dictionary<PieSlice, double> allocationUnderTable;

            DiscoveryLogic.UI.Layouts.WrappedControls.Button rebalanceButton;
            DiscoveryLogic.UI.Layouts.WrappedControls.Button rebalanceExecuteButton;
            DiscoveryLogic.UI.Layouts.WrappedControls.Button rebalanceCancelButton;

            private PieSlice hoverOverSlice;
            private MouseEventArgs test;

            string selectedInvStyle = "Balanced Growth";

            private double initialPieTotal;

        #endregion

        #region Constructors

            public Portfolio()
        {
            // Required to initialize variables
            InitializeComponent();

            mouseEventManager = new MouseManager();
            fundManager = new FundsManager();

            missingFundTypes = new List<FundTypes>();
            unwantedFundTypes = new List<FundTypes>();
            fundPanelList = new List<EnrollmentFund>();

            allocationOverTable = new Dictionary<PieSlice, double>();
            allocationUnderTable = new Dictionary<PieSlice, double>();

            // Add Sample Funds onto Fund Panel
            List<EnrollmentFund> listOfFunds = SetSampleFundPanel();

            // Create the pie
            Point pieCenter = new Point(265, 270.13);
            double pieRadius = 100;
            portfolioPie = new PieChart(pieCenter, pieRadius);
            portfolioPie.contributionChanged += new EventHandler(portfolioPie_contributionChanged);
            portfolioPie.contributionChanging += new EventHandler(portfolioPie_contributionChanging);
            portfolioPie.callAttachFund = AttachFund;

            portfolioPie.AddSlice(3000, 0.3, new EnrollmentFund(6, FundTypes.DomesticBonds, FindFundName(listOfFunds, FundTypes.DomesticBonds), 0, 0.3));
            portfolioPie.AddSlice(2500, 0.25, new EnrollmentFund(7, FundTypes.DomesticEquity, FindFundName(listOfFunds, FundTypes.DomesticEquity), 0, 0.5));
            portfolioPie.AddSlice(2500, 0.25, new EnrollmentFund(8, FundTypes.ForeignEquity, FindFundName(listOfFunds, FundTypes.ForeignEquity), 0, 0.2));
            portfolioPie.AddSlice(2000, 0.2, new EnrollmentFund(9, FundTypes.ForeignBonds, FindFundName(listOfFunds, FundTypes.ForeignBonds), 0, 0.2));

            portfolioPie.DrawSlices();
            PortfolioCanvas.Children.Add(portfolioPie);

            // Update total portfolio value
            TotalPortfolioValueText.Text = portfolioPie.TotalPieAmount.ToCurrency();
            initialPieTotal = portfolioPie.TotalPieAmount;

            // Create the buttons used on this screen
            CreateButtons();

            // Add Investment Style Buttons
            CreateInvestmentStyleButtons();

            // Create the overlays
            CreatePieOverlays(pieCenter, pieRadius);

            // Add Fund Legend
            CreateFundLegend();

            // Attach handlers to events
            AttachHandlers();

            // Update the tips panel
            UpdateTipPanel();

            // Check whether or not portfolio is over/under contributed
            CheckPortfolioContribution(0);
        }

        #endregion

        #region Helper Methods

            /// <summary>
            /// Look through a list of funds for a matching fund type.
            /// If found, return the name of the fund
            /// </summary>
            /// <param name="listOfFunds"></param>
            /// <param name="fundType"></param>
            /// <returns></returns>
            private string FindFundName(List<EnrollmentFund> listOfFunds, FundTypes fundType)
            {
                string name = fundType.ToString() + " Fund";

                for (int i = 0; i < listOfFunds.Count; i++)
                {
                    if (listOfFunds[i].FundType == fundType)
                    {
                        name = listOfFunds[i].FundName;
                        break;
                    }
                }

                return name;
            }



            private void CheckPortfolioContribution(double offset)
            {
                if (Math.Round(100 * (portfolioPie.TotalContributionPercent + offset)) != 100)
                {
                    ContributionExclamationText.Text = Math.Round(100 * (1 - portfolioPie.TotalContributionPercent + offset)) + "% left to allocate";

                    ContributionExclamation.Opacity = 1;
                    ContributionExclamationText.Opacity = 1;
                }
                else
                {
                    ContributionExclamation.Opacity = 0;
                    ContributionExclamationText.Opacity = 0;
                }
            }

            private void CreateButtons()
            {
                rebalanceButton = new DiscoveryLogic.UI.Layouts.WrappedControls.Button();
                rebalanceButton.Width = 110;
                rebalanceButton.Height = 60;
                rebalanceButton.Content = CreateCenteredContentTextBlock((string)Resources["Res_RebalanceButtonText"]);
                rebalanceButton.HorizontalAlignment = HorizontalAlignment.Right;
                rebalanceButton.Click += new RoutedEventHandler(OnRebalanceClicked);

                rebalanceExecuteButton = new DiscoveryLogic.UI.Layouts.WrappedControls.Button();
                rebalanceExecuteButton.Content = CreateCenteredContentTextBlock((string)Resources["Res_ExecuteButtonText"]);

                rebalanceExecuteButton.Width = 90;
                rebalanceExecuteButton.Height = 60;
                rebalanceExecuteButton.ReflectionVisibility = Visibility.Collapsed;
                rebalanceExecuteButton.FontSize = 16; 

                rebalanceExecuteButton.SetValue(Canvas.LeftProperty, 196.0);
                rebalanceExecuteButton.SetValue(Canvas.TopProperty, 176.84);
                rebalanceExecuteButton.Click += new RoutedEventHandler(OnRebalanceClicked);
                Rebalance_Popup.Children.Add(rebalanceExecuteButton);

                rebalanceCancelButton = new DiscoveryLogic.UI.Layouts.WrappedControls.Button();
                //JAIMERTODO:  rebalanceCancelButton.DimButton();
                rebalanceCancelButton.ReflectionVisibility = Visibility.Collapsed;
                rebalanceCancelButton.FontSize = 16; 

                rebalanceCancelButton.Width = 80;
                rebalanceCancelButton.Height = 60;
                rebalanceCancelButton.Content = CreateCenteredContentTextBlock((string)Resources["Res_CancelButtonText"]);
                rebalanceCancelButton.SetValue(Canvas.LeftProperty, 290.829);
                rebalanceCancelButton.SetValue(Canvas.TopProperty, 176.84);
                rebalanceCancelButton.Click += new RoutedEventHandler(OnRebalanceClicked);
                Rebalance_Popup.Children.Add(rebalanceCancelButton);
            }

            private void CreatePieOverlays(Point pieCenter, double pieRadius)
            {
                for (int i = 0; i < investmentStyleButtons.Length; i++)
                {
                    investmentStyleOverlays[i] = new PieOverlay(pieCenter, pieRadius - (pieRadius * 0.2));

                    switch (i)
                    {
                        case 0:
                            investmentStyleOverlays[i].InvStyleName = "Conservative";
                            investmentStyleOverlays[i].AddSlice(0.5, 0.5, new EnrollmentFund(0, FundTypes.DomesticBonds));
                            investmentStyleOverlays[i].AddSlice(0.3, 0.3, new EnrollmentFund(1, FundTypes.ForeignBonds));
                            investmentStyleOverlays[i].AddSlice(0.2, 0.2, new EnrollmentFund(2, FundTypes.DomesticEquity));
                            break;
                        case 2:
                            investmentStyleOverlays[i].InvStyleName = "Balanced";
                            investmentStyleOverlays[i].AddSlice(0.25, 0.25, new EnrollmentFund(0, FundTypes.Other));
                            investmentStyleOverlays[i].AddSlice(0.20, 0.20, new EnrollmentFund(1, FundTypes.DomesticEquity));
                            investmentStyleOverlays[i].AddSlice(0.25, 0.25, new EnrollmentFund(2, FundTypes.ForeignEquity));
                            investmentStyleOverlays[i].AddSlice(0.3, 0.3, new EnrollmentFund(3, FundTypes.ShortTerm));
                            break;
                        case 4:
                            investmentStyleOverlays[i].InvStyleName = "Balanced Growth";
                            investmentStyleOverlays[i].AddSlice(0.25, 0.25, new EnrollmentFund(0, FundTypes.DomesticBonds));
                            investmentStyleOverlays[i].AddSlice(0.25, 0.25, new EnrollmentFund(1, FundTypes.DomesticEquity));
                            investmentStyleOverlays[i].AddSlice(0.25, 0.25, new EnrollmentFund(2, FundTypes.ForeignEquity));
                            investmentStyleOverlays[i].AddSlice(0.25, 0.25, new EnrollmentFund(3, FundTypes.ForeignBonds));
                            break;
                        case 1:
                            investmentStyleOverlays[i].InvStyleName = "Growth";
                            investmentStyleOverlays[i].AddSlice(0.20, 0.20, new EnrollmentFund(0, FundTypes.DomesticBonds));
                            investmentStyleOverlays[i].AddSlice(0.25, 0.25, new EnrollmentFund(1, FundTypes.DomesticEquity));
                            investmentStyleOverlays[i].AddSlice(0.25, 0.25, new EnrollmentFund(2, FundTypes.ForeignEquity));
                            investmentStyleOverlays[i].AddSlice(0.3, 0.3, new EnrollmentFund(3, FundTypes.ShortTerm));
                            break;
                        case 3:
                            investmentStyleOverlays[i].InvStyleName = "Aggressive";
                            investmentStyleOverlays[i].AddSlice(0.3, 0.3, new EnrollmentFund(0, FundTypes.Other));
                            investmentStyleOverlays[i].AddSlice(0.15, 0.15, new EnrollmentFund(1, FundTypes.DomesticEquity));
                            investmentStyleOverlays[i].AddSlice(0.15, 0.15, new EnrollmentFund(2, FundTypes.ForeignEquity));
                            investmentStyleOverlays[i].AddSlice(0.4, 0.4, new EnrollmentFund(3, FundTypes.ShortTerm));
                            break;
                        default:
                            break;
                    }

                    investmentStyleOverlays[i].ColorSlicesOpaque();
                    investmentStyleOverlays[i].DrawSlices();
                    investmentStyleOverlays[i].HideFundIcons(true);
                    //investmentStyleOverlays[i].Opacity = 0;
                    PortfolioCanvas.Children.Add(investmentStyleOverlays[i]);
                }
            }

            private List<EnrollmentFund> SetSampleFundPanel()
            {

                List<EnrollmentFund> listOfFunds = fundManager.GetFunds();

                int count = 10;

                if (listOfFunds.Count < 10)
                {
                    count = listOfFunds.Count;
                }

                // Create funds
                for (int i = 0; i < count; i++)
                {
                    EnrollmentFund fundTab = listOfFunds[i];

                    // Set properties
                    fundTab.enrollmentFundDrag += new EventHandler(OnEnrollmentFundDrag);
                    fundTab.enrollmentFundMouseDown += new EventHandler(OnEnrollmentFundMouseDown);
                    fundTab.enrollmentFundMouseUp += new EventHandler(OnEnrollmentFundMouseUp);
                    fundTab.SetValue(Canvas.LeftProperty, 35.0);
                    fundTab.SetValue(Canvas.TopProperty, listOfFunds[i].Id * 40.0);
                    fundTab.SetValue(Canvas.ZIndexProperty, 2 + FundPanelFundContainer.Children.Count);

                    // Add to canvas
                    FundPanelFundContainer.Children.Add(fundTab);

                    // Add to fund panel list
                    fundPanelList.Add(fundTab);
                }

                return listOfFunds;
            }

            private void CreateFundLegend()
            {
                fundLegendIcons[0] = new FundLegend(FundTypes.DomesticEquity, -60, 7);
                fundLegendIcons[0].SetValue(Canvas.LeftProperty, 90.0);
                fundLegendIcons[0].SetValue(Canvas.TopProperty, 40.0);

                fundLegendIcons[1] = new FundLegend(FundTypes.DomesticBonds, 50, 7);
                fundLegendIcons[1].SetValue(Canvas.LeftProperty, 122.333);
                fundLegendIcons[1].SetValue(Canvas.TopProperty, 40.0);

                fundLegendIcons[2] = new FundLegend(FundTypes.ForeignEquity, -60, 7);
                fundLegendIcons[2].SetValue(Canvas.LeftProperty, 90.0);
                fundLegendIcons[2].SetValue(Canvas.TopProperty, 79.996);

                fundLegendIcons[3] = new FundLegend(FundTypes.ForeignBonds, 50, 7);
                fundLegendIcons[3].SetValue(Canvas.LeftProperty, 122.333);
                fundLegendIcons[3].SetValue(Canvas.TopProperty, 79.996);

                fundLegendIcons[4] = new FundLegend(FundTypes.Other, -60, 7);
                fundLegendIcons[4].SetValue(Canvas.LeftProperty, 90.0);
                fundLegendIcons[4].SetValue(Canvas.TopProperty, 119.992);

                fundLegendIcons[5] = new FundLegend(FundTypes.ShortTerm, 50, 7);
                fundLegendIcons[5].SetValue(Canvas.LeftProperty, 122.333);
                fundLegendIcons[5].SetValue(Canvas.TopProperty, 119.992);

                for (int i = 0; i < fundLegendIcons.Length; i++)
                {
                    Asset_Classes.Children.Add(fundLegendIcons[i]);
                }
            }

            private void CreateInvestmentStyleButtons()
            {
                // They're added in this non-intuitive ordering because
                // when they're added to the canvas using the for loop, the 
                // bottom-most button has the highest z index
                investmentStyleButtons[0] = new ToggleButton();
                investmentStyleButtons[0].Width = 115;
                investmentStyleButtons[0].Content = "Conservative";
                investmentStyleButtons[0].SetValue(Canvas.LeftProperty, 10.5);
                investmentStyleButtons[0].SetValue(Canvas.TopProperty, 93.667);

                investmentStyleButtons[1] = new ToggleButton();
                investmentStyleButtons[1].Width = 115;
                investmentStyleButtons[1].Content = "Growth";
                investmentStyleButtons[1].SetValue(Canvas.LeftProperty, 142.542);
                investmentStyleButtons[1].SetValue(Canvas.TopProperty, 93.667);

                investmentStyleButtons[2] = new ToggleButton();
                investmentStyleButtons[2].Width = 115;
                investmentStyleButtons[2].Content = "Balanced";
                investmentStyleButtons[2].SetValue(Canvas.LeftProperty, 10.5);
                investmentStyleButtons[2].SetValue(Canvas.TopProperty, 123.667);


                investmentStyleButtons[3] = new ToggleButton();
                investmentStyleButtons[3].Width = 115;
                investmentStyleButtons[3].Content = "Aggressive";
                investmentStyleButtons[3].SetValue(Canvas.LeftProperty, 142.542);
                investmentStyleButtons[3].SetValue(Canvas.TopProperty, 123.667);

                investmentStyleButtons[4] = new ToggleButton();
                investmentStyleButtons[4].Width = 115;
                investmentStyleButtons[4].Content = "Balanced Growth";
                investmentStyleButtons[4].SetValue(Canvas.LeftProperty, 65.634);
                investmentStyleButtons[4].SetValue(Canvas.TopProperty, 153.667);

                for (int i = 0; i < investmentStyleButtons.Length; i++)
                {
                    // Add to canvas
                    investmentStyleButtons[i].IsThreeState = false;
                    Inv_Styles.Children.Add(investmentStyleButtons[i]);
                }
            }

            private void AttachHandlers()
            {
                //this.MouseLeftButtonUp += new MouseButtonEventHandler(Screen_MouseLeftButtonUp);

                FundPanel.MouseEnter += new MouseEventHandler(FundPanel_MouseEnter);
                FundPanel.MouseLeave += new MouseEventHandler(FundPanel_MouseLeave);

                for (int i = 0; i < investmentStyleButtons.Length; i++)
                {
                    // Set handlers
                    // investmentStyleButtons[i].MouseEnter += mouseEventManager.OnMouseEnterHand;
                    // investmentStyleButtons[i].MouseEnter += new MouseEventHandler(InvestmentStyleButton_MouseEnter);
                    // investmentStyleButtons[i].MouseLeave += mouseEventManager.OnMouseLeaveArrow;
                    // investmentStyleButtons[i].MouseLeave += new MouseEventHandler(InvestmentStyleButton_MouseLeave);
                    // investmentStyleButtons[i].MouseLeftButtonUp += new MouseButtonEventHandler(InvestmentStyleButton_MouseLeftButtonUp);
                    investmentStyleButtons[i].Click += new RoutedEventHandler(InvestmentStyleButton_MouseLeftButtonUp);
                }

                for (int i = 0; i < fundLegendIcons.Length; i++)
                {
                    fundLegendIcons[i].MouseEnter += new MouseEventHandler(FundLegendIcon_MouseEnter);
                    fundLegendIcons[i].MouseLeave += new MouseEventHandler(FundLegendIcon_MouseLeave);
                }
            }

            private void CheckAllocation()
            {
                // Determine current investment style
                for (int i = 0; i < investmentStyleOverlays.Length; i++)
                {
                    if (investmentStyleOverlays[i].InvStyleName == selectedInvStyle)
                    {
                        currentOverlay = investmentStyleOverlays[i];
                        break;
                    }
                }

                // Find out what funds the new investment style doesn`t include
                // but exists in the current allocation
                List<PieSlice> portfolioPieSliceList = portfolioPie.GetPieSliceList();
                List<FundTypes> testedFunds = new List<FundTypes>();

                // Clear temporary lists
                missingFundTypes.Clear();
                unwantedFundTypes.Clear();

                double numFunds = portfolioPieSliceList.Count;
                bool isContains = false;

                for (int i = 0; i < numFunds; i++)
                {
                    // If we haven`t tested this fund yet,
                    if (!testedFunds.Contains(portfolioPieSliceList[i].Fund.FundType))
                    {
                        // Check if the current investment style overlay contains this fund
                        isContains = currentOverlay.FundExists(portfolioPieSliceList[i].Fund.FundType);

                        // Add this fund to the tested list
                        testedFunds.Add(portfolioPieSliceList[i].Fund.FundType);
                    }

                    // If the current investment style overlay contains this fund
                    if (!isContains)
                    {
                        unwantedFundTypes.Add(portfolioPieSliceList[i].Fund.FundType);
                    }
                }

                // Find out what funds the investment style needs but
                // doesn't exist in the current allocation
                List<PieSlice> overlayPieSliceList = currentOverlay.GetPieSliceList();
                numFunds = overlayPieSliceList.Count;
                isContains = false;

                for (int i = 0; i < numFunds; i++)
                {
                    // Check if overlay fund exists in current allocation pie
                    isContains = portfolioPie.FundExists(overlayPieSliceList[i].Fund.FundType);

                    // If not, then it needs to be added so put it in the list of fund
                    // types to add
                    if (!isContains)
                    {
                        missingFundTypes.Add(overlayPieSliceList[i].Fund.FundType);
                        overlayPieSliceList[i].MissingFund = true;
                        overlayPieSliceList[i].pieSliceMouseEnter += new MouseEventHandler(OnMissingFund_MouseEnter);
                        overlayPieSliceList[i].pieSliceMouseLeave += new MouseEventHandler(OnMissingFund_MouseLeave);
                    }
                    else
                    {
                        overlayPieSliceList[i].MissingFund = false;
                        overlayPieSliceList[i].pieSliceMouseEnter -= new MouseEventHandler(OnMissingFund_MouseEnter);
                        overlayPieSliceList[i].pieSliceMouseLeave -= new MouseEventHandler(OnMissingFund_MouseLeave);
                    }
                }

                if (missingFundTypes.Count == 0)
                {
                    OnRebalanceClicked(this, new RoutedEventArgs());
                }

                UpdateTipPanel();
            }

            /// <summary>
            /// This method changes the parent of a given fund from the fund panel
            /// to the pie chart panel while maintaining the same position on the screen.
            /// This is to facilitate dragging across containers.
            /// </summary>
            /// <param name="fund">The fund being dragged</param>
            private void FundPanelToPiePanel(EnrollmentFund fund, Canvas fromParent, Canvas toParent, MouseEventArgs e)
            {
                // Position of the fund
                double fundLeft = (double)fund.GetValue(Canvas.LeftProperty);
                double fundTop = (double)fund.GetValue(Canvas.TopProperty);

                // Distance from old parent and new parent
                Point fromPos = e.GetPosition(fromParent);
                Point toPos = e.GetPosition(toParent);

                // Differences
                Point deltaPos = new Point(fromPos.X - toPos.X, fromPos.Y - toPos.Y);
                Point newPos = new Point(fundLeft - deltaPos.X, fundTop - deltaPos.Y);

                // Set new values
                fund.SetValue(Canvas.LeftProperty, newPos.X);
                fund.SetValue(Canvas.TopProperty, newPos.Y);

                // Remove from old parent canvas
                fromParent.Children.Remove(fund);

                // Add to new parent canvas
                toParent.Children.Add(fund);
            }

            /// <summary>
            /// Updates the text in the Tip Panel according to any missing/unwanted
            /// fund types between the pie chart and the investment style overlay
            /// </summary>
            private void UpdateTipPanel()
            {
                // Clear static tip panel
                StaticTipPanel.Children.Clear();

                if (missingFundTypes.Count > 0)
                {
                    TextBlock statement = CreateTipPanelTextBlock();
                    statement.Text = string.Format((string)Resources["Res_MissingFunds1stMessage"],
                         selectedInvStyle);
                    StaticTipPanel.Children.Add(statement);

                    statement = new TextBlock();
                    statement.Text = " ";
                    StaticTipPanel.Children.Add(statement);

                    statement = CreateTipPanelTextBlock();
                    statement.Text = (string)Resources["Res_MissingFunds2ndMessage"];
                    StaticTipPanel.Children.Add(statement);
                }
                else if (allocationOverTable.Count > 0 || allocationUnderTable.Count > 0)
                {
                    TextBlock statement = CreateTipPanelTextBlock();
                    statement.Text = string.Format((string)Resources["Res_NotBalanced1stMessage"], selectedInvStyle);
                    StaticTipPanel.Children.Add(statement);

                    statement = CreateTipPanelTextBlock();
                    statement.Text = " ";
                    StaticTipPanel.Children.Add(statement);

                    statement = CreateTipPanelTextBlock();
                    statement.Text = (string)Resources["Res_NotBalanced2ndMessage"];
                    StaticTipPanel.Children.Add(statement);

                    StaticTipPanel.Children.Add(rebalanceButton);
                }
                else
                {
                    TextBlock statement = CreateTipPanelTextBlock();
                    statement.Text = string.Format((string)Resources["Res_Compare1stMessage"], selectedInvStyle);
                    StaticTipPanel.Children.Add(statement);

                    statement = CreateTipPanelTextBlock();
                    statement.Text = (string)Resources["Res_Compare2ndMessage"];
                    StaticTipPanel.Children.Add(statement);

                    statement = CreateTipPanelTextBlock();
                    statement.Text = " ";
                    StaticTipPanel.Children.Add(statement);

                    statement = CreateTipPanelTextBlock();
                    statement.Text = (string)Resources["Res_Compare3rdMessage"];
                    StaticTipPanel.Children.Add(statement);
                }

                /*
                for (int i = 0; i < unwantedFundTypes.Count; i++)
                {
                    TextBlock statement = new TextBlock();
                    statement.Width = 470;
                    statement.TextWrapping = TextWrapping.Wrap;
                    statement.FontSize = 14;
                    statement.SetValue(TextBlock.ForegroundProperty, "#FF1D62AF");
                    statement.SetValue(TextBlock.FontFamilyProperty, "Trebuchet MS");
                    statement.Text = "You have one or more fund types that this investment style does not include.";
                    StaticTipPanel.Children.Add(statement);
                }
                */
            }

            /// <summary>
            /// Creates a textblock with the attributes/styling for the
            /// static tip panel
            /// </summary>
            /// <returns>Returns a textblock</returns>
            private TextBlock CreateTipPanelTextBlock()
            {
                TextBlock statement = new TextBlock();
                statement.Width = 470;
                statement.Style = (Style)Application.Current.Resources["InfoTipBody"];
                return statement;
            }

            private TextBlock CreateRebalancePanelTextBlock()
            {
                TextBlock statement = new TextBlock();
                statement.Width = 350;
                statement.Style = (Style)Application.Current.Resources["PopupBody"];

                return statement;
            }

            private TextBlock CreateCenteredContentTextBlock(string text)
            {
                TextBlock textBlock = new TextBlock();
                textBlock.Text = text;
                textBlock.TextAlignment = TextAlignment.Center;
                return textBlock;
            }

        #endregion


        #region Public Methods

            public void FadeCanvasAnimation(bool show)
        {
            if (show == true)
            {
                FadePortfolioCanvasKeyFrame.Value = 1;
                FadePortfolioCanvas.Begin();
            }
            else
            {
                FadePortfolioCanvasKeyFrame.Value = 0;
                FadePortfolioCanvas.Begin();
            }
        }

        #endregion

        #region Event Handlers

            void portfolioPie_contributionChanged(object sender, EventArgs e)
            {
                CheckPortfolioContribution(0);
            }

            void portfolioPie_contributionChanging(object sender, EventArgs e)
            {
                DiscoveryLogic.UI.Layouts.Models.CustomEventArgs args = (DiscoveryLogic.UI.Layouts.Models.CustomEventArgs)e;

                CheckPortfolioContribution(args.ContributionOffset);
            }

            /*
            private void Screen_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
            {
                // Slide fund panel back in
                FundPanel_MouseLeave(this, new MouseButtonEventArgs());
            }
            */

            /// <summary>
            /// Handles the MouseLeave event of the FundPanel control.
            /// </summary>
            /// <param name="sender">The source of the event.</param>
            /// <param name="e">The <see cref="System.Windows.Input.MouseEventArgs"/> instance containing the event data.</param>
            void FundPanel_MouseLeave(object sender, MouseEventArgs e)
            {
                SlideInFundPanel.Begin();
            }

            /// <summary>
            /// Handles the MouseEnter event of the FundPanel control.
            /// </summary>
            /// <param name="sender">The source of the event.</param>
            /// <param name="e">The <see cref="System.Windows.Input.MouseEventArgs"/> instance containing the event data.</param>
            void FundPanel_MouseEnter(object sender, MouseEventArgs e)
            {
                SlideOutFundPanel.Begin();
            }

            void InvestmentStyleButton_MouseLeftButtonUp(object sender, RoutedEventArgs e)
            {
                // Disallow chart actions
                portfolioPie.ChartActionsAllowed = false;

                // Reset previous investment style
                if (currentOverlay != null)
                {
                    //currentOverlay.Opacity = 0;
                    currentOverlay.ScaleOverlay(false);
                    currentOverlay.SetValue(Canvas.ZIndexProperty, 0);
                }

                if (((ToggleButton)sender).IsChecked == true)
                {
                    // Set current investment style to the one just clicked
                    // JAIMERTODO: selectedInvStyle = ((InvestmentStyleButton)sender).GetStyleName();
                    selectedInvStyle = ((ToggleButton)sender).Content.ToString();

                    for (int i = 0; i < investmentStyleOverlays.Length; i++)
                    {
                        if (investmentStyleOverlays[i].InvStyleName == selectedInvStyle)
                        {
                            investmentStyleOverlays[i].ScaleOverlay(true);
                            investmentStyleOverlays[i].SetValue(Canvas.ZIndexProperty, 1);
                            currentOverlay = investmentStyleOverlays[i];

                            // Check for inconsistancies between overlay and pie allocation
                            CheckAllocation();
                            break;
                        }
                    }
                }
                else
                {
                    for (int i = 0; i < investmentStyleOverlays.Length; i++)
                    {
                        if (investmentStyleOverlays[i].InvStyleName == selectedInvStyle)
                        {

                            investmentStyleOverlays[i].ScaleOverlay(false);
                            currentOverlay = null;
                            break;
                        }
                    }
                    portfolioPie.ChartActionsAllowed = true;
                    unwantedFundTypes.Clear();
                    missingFundTypes.Clear();
                    allocationOverTable.Clear();
                    allocationUnderTable.Clear();
                    UpdateTipPanel();
                }

                // Toggle button
                // ((ToggleButton)sender).ToggleStatus = !((InvestmentStyleButton)sender).ToggleStatus;

                if (currentInvestmentStyleButton != null &&
                !currentInvestmentStyleButton.Equals((ToggleButton)sender))
                {
                    currentInvestmentStyleButton.IsChecked = false;
                }

                // Set current investment style button to the button just clicked
                currentInvestmentStyleButton = (ToggleButton)sender;
            }

            void InvestmentStyleButton_MouseEnter(object sender, MouseEventArgs e)
            {
                /*
                InvestmentStyleButton invStyle = (InvestmentStyleButton)sender;

                for (int i = 0; i < investmentStyleOverlays.Length; i++)
                {
                    investmentStyleOverlays[i].Opacity = 0;                    
                }

                for (int i = 0; i < investmentStyleOverlays.Length; i++)
                {
                    if (investmentStyleOverlays[i].InvStyleName == invStyle.GetStyleName())
                    {
                        investmentStyleOverlays[i].Opacity = 1;
                        break;
                    }
                }
                */
            }

            void InvestmentStyleButton_MouseLeave(object sender, MouseEventArgs e)
            {
                /*
                for (int i = 0; i < investmentStyleOverlays.Length; i++)
                {
                    if (investmentStyleOverlays[i].InvStyleName == CurrentInvStyleLabel.Text)
                    {
                        investmentStyleOverlays[i].Opacity = 1;
                    }
                    else
                    {
                        investmentStyleOverlays[i].Opacity = 0;
                    }
                }
                */
            }

            void FundLegendIcon_MouseEnter(object sender, MouseEventArgs e)
            {
                FundLegend legend = (FundLegend)sender;
                portfolioPie.LiftSlices(legend.GetFundType());
            }

            void FundLegendIcon_MouseLeave(object sender, MouseEventArgs e)
            {
                FundLegend legend = (FundLegend)sender;
                portfolioPie.LowerSlices(legend.GetFundType());
            }

            /// <summary>
            /// As the fund is being dragged, check if its
            /// over a pie slice. If so, highlight the slice.
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void OnEnrollmentFundDrag(object sender, EventArgs e)
            {
                MouseEventArgs args = (MouseEventArgs)e;
                EnrollmentFund fund = (EnrollmentFund)sender;

                // Check if it overlaps pie slices                
                PieOverlay pc = currentOverlay;
                if (pc != null)
                {
                    bool hit = pc.HitTestHighlight(args, fund.FundType);
                }
            }

            /// <summary>
            /// When the user clicks a fund, change the funds
            /// parent from the fund panel to the enrollment canvas.
            /// This is to make it have the highest z index.
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void OnEnrollmentFundMouseDown(object sender, EventArgs e)
            {
                MouseEventArgs args = (MouseEventArgs)e;
                EnrollmentFund fund = (EnrollmentFund)sender;

                FundPanelToPiePanel(fund, FundPanelFundContainer, PortfolioCanvas, args);

                // Remove from fund panel list
                fundPanelList.Remove(fund);
            }

            /// <summary>
            /// When the user releases a fund, check if it is over a pie slice.
            /// If not, move it back to fund panel
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void OnEnrollmentFundMouseUp(object sender, EventArgs e)
            {
                MouseEventArgs args = (MouseEventArgs)e;
                EnrollmentFund fund = (EnrollmentFund)sender;
                bool hit = false;

                // Test if we're adding this fund
                PieOverlay pc = currentOverlay;
                if (pc != null)
                {
                    hit = pc.HitTestHighlight(args, fund.FundType);
                }

                if (hit == true)
                {
                    fund.SetValue(Canvas.LeftProperty, 0.0);
                    fund.SetValue(Canvas.TopProperty, 0.0);
                    PortfolioCanvas.Children.Remove(fund);

                    List<PieSlice> pieSliceList = currentOverlay.GetPieSliceList();

                    // Add the fund to the pie
                    portfolioPie.AddFund(fund, 0);

                    // For the slice just added, set the dummy slice property                    
                    pieSliceList = portfolioPie.GetPieSliceList();
                    for (int i = 0; i < pieSliceList.Count; i++)
                    {
                        if (pieSliceList[i].Fund.FundType == fund.FundType)
                        {
                            pieSliceList[i].IsDummySlice = true;
                        }
                    }


                    // Remove fund from fund panel list
                    fundPanelList.Remove(fund);

                    // Lower all slices in the overlay
                    currentOverlay.LowerAllSlices();

                    // After addition of needed fund, now check if missing anymore
                    CheckAllocation();

                    SlideInFundPanel.Begin();
                }
                else
                {
                    // Move fund from enrollment canvas back to fund list canvas
                    PortfolioCanvas.Children.Remove(fund);
                    FundPanelFundContainer.Children.Add(fund);

                    // Add to fund panel list
                    fundPanelList.Add(fund);

                    fund.SetValue(Canvas.LeftProperty, 35.0);
                    fund.SetValue(Canvas.TopProperty, Convert.ToDouble(fund.Id * 40.0));

                    fund.ResetPosition();
                }
            }

            private void FilterFundPanel(FundTypes filterByThisFundType)
            {
                // Clear fund panel
                FundPanelFundContainer.Children.Clear();

                // Repopulate with only funds of a specific type
                for (int i = 0; i < fundPanelList.Count; i++)
                {
                    if (fundPanelList[i].FundType == filterByThisFundType)
                    {
                        fundPanelList[i].SetValue(Canvas.TopProperty, Convert.ToDouble(FundPanelFundContainer.Children.Count * 40.0));
                        FundPanelFundContainer.Children.Add(fundPanelList[i]);
                    }
                }
            }

            private void FilterFundPanel()
            {
                // Clear fund panel
                FundPanelFundContainer.Children.Clear();

                for (int j = 0; j < EnrollmentFund.numFundTypes; j++)
                {
                    // Read all funds from fund panel list
                    for (int i = 0; i < fundPanelList.Count; i++)
                    {
                        if (fundPanelList[i].FundType == (FundTypes)j)
                        {
                            fundPanelList[i].SetValue(Canvas.TopProperty, Convert.ToDouble(FundPanelFundContainer.Children.Count * 40.0));
                            fundPanelList[i].Id = FundPanelFundContainer.Children.Count;
                            fundPanelList[i].SetValue(Canvas.ZIndexProperty, FundPanelFundContainer.Children.Count);
                            FundPanelFundContainer.Children.Add(fundPanelList[i]);
                        }
                    }
                }
            }

            private void Rebalance(bool execute)
            {
                // Remove unwanted slices
                List<PieSlice> portfolioPieSliceList = portfolioPie.GetPieSliceList();

                foreach (FundTypes fundType in unwantedFundTypes)
                {
                    for (int i = 0; i < portfolioPieSliceList.Count; i++)
                    {
                        if (portfolioPieSliceList[i].Fund.FundType == fundType)
                        {
                            // Reallocate the money in this fund to another fund
                            double fundAmount = portfolioPieSliceList[i].SliceAmount;
                            ApplyMoneyToUnderAllocatedFunds(portfolioPieSliceList[i].Fund, fundAmount, allocationUnderTable, execute);

                            if (execute)
                            {
                                portfolioPie.RebalanceRemoveSlice(portfolioPieSliceList[i]);
                            }
                        }
                    }
                }

                // Transfer money from over allocated funds to the underallocated funds
                foreach (KeyValuePair<PieSlice, double> pair in allocationOverTable)
                {
                    PieSlice slice = (PieSlice)pair.Key;
                    double overAmount = (double)pair.Value;

                    // Reallocate the money in this fund to another fund
                    ApplyMoneyToUnderAllocatedFunds(slice.Fund, overAmount, allocationUnderTable, execute);

                    if (execute)
                    {
                        slice.SliceAmount = slice.SliceAmount - overAmount;
                    }
                }

                if (execute)
                {
                    // Find out what contribution percent this investment style
                    // has for this type of fund and set it
                    double contribPercent = 0;
                    List<PieSlice> overlaySliceList = currentOverlay.GetPieSliceList();
                    Dictionary<FundTypes, List<PieSlice>> pieFundTable = portfolioPie.GetFunds();

                    for (int i = 0; i < overlaySliceList.Count; i++)
                    {
                        contribPercent = overlaySliceList[i].SliceContribution;
                        FundTypes currentFundType = overlaySliceList[i].Fund.FundType;

                        // If the portfolio contains this asset class, retrieve it and set contrib percent
                        if (pieFundTable.ContainsKey(currentFundType))
                        {
                            List<PieSlice> pieMatchedFundList = pieFundTable[currentFundType];

                            for (int j = 0; j < pieMatchedFundList.Count; j++)
                            {
                                pieMatchedFundList[j].SliceContribution = contribPercent / pieMatchedFundList.Count;
                            }
                        }

                    }
                }

                // Set the dummy property for all slices to false and update tips panel
                if (execute)
                {
                    for (int i = 0; i < portfolioPieSliceList.Count; i++)
                    {
                        portfolioPieSliceList[i].IsDummySlice = false;
                    }

                    // Post rebalance actions
                    CurrentInvStyleLabel.Text = selectedInvStyle;
                    allocationUnderTable.Clear();
                    allocationOverTable.Clear();
                    CheckPortfolioContribution(0);
                    UpdateTipPanel();
                }

                portfolioPie.DrawSlices();
            }

            private void ApplyMoneyToUnderAllocatedFunds(EnrollmentFund fromFund, double amount, Dictionary<PieSlice, double> allocationUnderTable, bool execute)
            {
                List<PieSlice> portfolioPieList = portfolioPie.GetPieSliceList();

                double amountToAllocate = amount;

                foreach (PieSlice slice in portfolioPieList)
                {
                    if (allocationUnderTable.ContainsKey(slice))
                    {
                        // This is the amount that needs to be applied to this allocation to 
                        // make it the recommended amount for the current investment style
                        double underAmount = (double)allocationUnderTable[slice];

                        // If this under allocation hasn`t been corrected yet...
                        if (underAmount != 0 && amountToAllocate < Math.Abs(underAmount))
                        {
                            // Amount to allocate is less than the under allocation amount
                            // Apply it to the under amount and update the table
                            if (execute)
                            {
                                slice.SliceAmount = slice.SliceAmount + amountToAllocate;
                            }
                            else if (Math.Round(amountToAllocate, 2) != 0)
                            {
                                // Add a line to the rebalance stack panel
                                TextBlock statement = CreateRebalancePanelTextBlock();
                                statement.Text = string.Format((string)Resources["Res_RebalanceTransferText"],
                                    Math.Round(amountToAllocate, 2).ToCurrency(), fromFund.FundName, slice.Fund.FundName);
                                RebalanceStackPanel.Children.Add(statement);
                            }
                            allocationUnderTable[slice] = underAmount + amountToAllocate;

                            // Add a line to the rebalance stack panel
                        }
                        else if (underAmount != 0 && amountToAllocate >= Math.Abs(underAmount))
                        {
                            // Amount is greater than the under allocation amount
                            // Apply it to the under amount and apply the rest to the next fund 
                            // that is under allocated.
                            if (execute)
                            {
                                slice.SliceAmount = slice.SliceAmount + Math.Abs(underAmount);
                            }
                            else
                            {
                                // Add a line to the rebalance stack panel
                                TextBlock statement = CreateRebalancePanelTextBlock();
                                statement.Text = string.Format((string)Resources["Res_RebalanceTransferText"],
                                    Math.Round(Math.Abs(underAmount), 2).ToCurrency(), fromFund.FundName, slice.Fund.FundName);
                                RebalanceStackPanel.Children.Add(statement);
                            }
                            allocationUnderTable[slice] = 0;
                            amountToAllocate -= Math.Abs(underAmount);

                        } // end if                      
                    } // end if
                } // end foreach
            }

            /// <summary>
            /// Given a fund, attach it to the fund panel canvas
            /// </summary>
            /// <param name="fund"></param>
            private void AttachFund(EnrollmentFund fund)
            {
                // Add fund to canvas
                FundPanelFundContainer.Children.Add(fund);
                fundPanelList.Add(fund);

                // Clear and re-add handlers
                fund.enrollmentFundDrag -= new EventHandler(OnEnrollmentFundDrag);
                fund.enrollmentFundMouseDown -= new EventHandler(OnEnrollmentFundMouseDown);
                fund.enrollmentFundMouseUp -= new EventHandler(OnEnrollmentFundMouseUp);

                fund.enrollmentFundDrag += new EventHandler(OnEnrollmentFundDrag);
                fund.enrollmentFundMouseDown += new EventHandler(OnEnrollmentFundMouseDown);
                fund.enrollmentFundMouseUp += new EventHandler(OnEnrollmentFundMouseUp);

                // Reset properties
                fund.ShrinkIcon();
                fund.SetValue(Canvas.LeftProperty, 35.0);
                fund.SetValue(Canvas.TopProperty, Convert.ToDouble(fund.Id * 40.0));
                fund.SetValue(Canvas.ZIndexProperty, fund.Id);
                fund.ResetPosition();

                // Show funds on the funds panel
                FilterFundPanel();

                // Update contribution allocation
                CheckPortfolioContribution(0);
            }

        #endregion

        #region Event Handlers

            private void OnMissingFund_MouseEnter(object sender, MouseEventArgs e)
            {
                // Filter funds panel by a specific fund
                PieSlice slice = (PieSlice)sender;
                FundTypes fundType = slice.Fund.FundType;

                FilterFundPanel(fundType);

                // Show guidance tooltip
                slice.ShowMissingFundIndicatorToolTip(true);

                // 
                if (hoverOverSlice != null)
                {
                    hoverOverSlice.SetValue(Canvas.ZIndexProperty, 0);
                }
                slice.SetValue(Canvas.ZIndexProperty, 1);

                // Slide out fund
                SlideOutFundPanel.Begin();

                // Start timer to slide fund panel back in
                FiveSecondDelay.Begin();

                // Update reference to current slice being hovered over
                hoverOverSlice = slice;


                test = e;
            }

            private void OnMissingFund_MouseLeave(object sender, MouseEventArgs e)
            {
                PieSlice slice = (PieSlice)sender;
                slice.ShowMissingFundIndicatorToolTip(false);
            }

            private void OnRebalanceClicked(object sender, RoutedEventArgs e)
            {
                bool execute;

                if (sender.Equals(rebalanceExecuteButton))
                {
                    execute = true;
                }
                else
                {
                    execute = false;
                    RebalanceStackPanel.Children.Clear();
                }

                Dictionary<FundTypes, List<PieSlice>> fundsTable = portfolioPie.GetFunds();
                allocationOverTable = new Dictionary<PieSlice, double>();
                allocationUnderTable = new Dictionary<PieSlice, double>();

                List<PieSlice> overlayPieSliceList = currentOverlay.GetPieSliceList();


                for (int i = 0; i < overlayPieSliceList.Count; i++)
                {
                    FundTypes overlayFundType = overlayPieSliceList[i].Fund.FundType;
                    double overlayAllocationPercentage = overlayPieSliceList[i].SliceAmount;

                    double pieAllocationPercentage = 0;
                    double pieAllocationValue = 0;
                    double offsetAmount = 0;

                    List<PieSlice> pieSlicesList = fundsTable[overlayFundType];

                    for (int j = 0; j < pieSlicesList.Count; j++)
                    {
                        pieAllocationValue += pieSlicesList[j].SliceAmount;
                    }

                    pieAllocationPercentage = pieAllocationValue / portfolioPie.TotalPieAmount;
                    offsetAmount = pieAllocationPercentage - overlayAllocationPercentage;

                    for (int j = 0; j < pieSlicesList.Count; j++)
                    {
                        double offsetAmountValue;

                        if (pieAllocationPercentage == 0)
                        {
                            offsetAmountValue = offsetAmount * pieSlicesList[j].TotalPieAmount;
                        }
                        else
                        {
                            offsetAmountValue = (offsetAmount / pieAllocationPercentage) * pieSlicesList[j].SliceAmount;
                        }

                        // See how much pieAllocationPercentage differs from overlayAllocationPercentage
                        if (pieAllocationPercentage > overlayAllocationPercentage * 1.01)
                        {
                            allocationOverTable.Add(pieSlicesList[j], offsetAmountValue);
                        }
                        else if (pieAllocationPercentage < overlayAllocationPercentage * 0.99)
                        {
                            allocationUnderTable.Add(pieSlicesList[j], offsetAmountValue);
                        }
                    }
                }

                // Update the text on the rebalance popup dialog
                Rebalance(execute);

                if (execute)
                {
                    // Ensure all fund values are correct by setting them to be
                    // contribution * portfolio value
                    List<PieSlice> portfolioPieSliceList = portfolioPie.GetPieSliceList();

                    for (int i = 0; i < portfolioPieSliceList.Count; i++)
                    {
                        portfolioPieSliceList[i].Fund.FundValue = portfolioPieSliceList[i].Fund.ContributionPercent * initialPieTotal;
                    }
                }

                if (sender.Equals(rebalanceButton))
                {
                    Rebalance_Popup.SetValue(Canvas.ZIndexProperty, 2);
                    Rebalance_Popup.Opacity = 1;
                }
                else
                {
                    Rebalance_Popup.SetValue(Canvas.ZIndexProperty, 0);
                    Rebalance_Popup.Opacity = 0;

                    // Update the tips panel
                    UpdateTipPanel();
                }
            }

            private void OnSlideInFundPanelComplete(object sender, EventArgs e)
            {
                if (FundPanelTranslate.X == 0)
                {
                    FilterFundPanel();
                }
            }

            private void OnDelayComplete(object sender, EventArgs e)
            {
                SlideInFundPanel.Begin();
            }

        #endregion

    }
}
